
#include "BlackScholes.hpp"

#include <math.h>
#include <errno.h>

using namespace provident;

static double const sqrt2(sqrt(2));

double 
BlackScholes::valuate(VanillaOption const& option,
                      double const underlyerPrice,
                      double const volatility,
                      double const riskFreeRate)
{
    // Look up square root of expiry
    double* expirySqrtPtr(NULL);
    double expirySqrt(0.0);
    if( _expirySqrts.find(option.expiryYears(),expirySqrtPtr) ) {
        expirySqrt = *expirySqrtPtr;
    } else {
        expirySqrt = sqrt(option.expiryYears());
        _expirySqrts[option.expiryYears()] = expirySqrt;
    }
        

    double const foo(volatility*expirySqrt);
    double const expMinusRT(exp(-riskFreeRate*option.expiryYears()));
    double const d1((log(underlyerPrice/option.strikePrice()) + (riskFreeRate+(volatility*volatility)/2)*option.expiryYears())/foo);
    double const d2(d1 - foo);

    double const callPrice(underlyerPrice*0.5*erfc(-d1/sqrt2) - option.strikePrice()*expMinusRT*0.5*erfc(-d2/sqrt2));
    if( option.type() == VanillaOption::PUT ) {
        return option.strikePrice()*expMinusRT-underlyerPrice+callPrice;
    } else {
        return callPrice;
    }
}

